import os
import json
from typing import Dict, Any, Optional, List
import logging

class ConfigManager:
    """
    配置管理器类，负责加载、保存和验证应用程序配置
    """
    def __init__(self, config_file: str = 'config.json'):
        """
        初始化配置管理器
        :param config_file: 配置文件路径
        """
        self.config_file = config_file
        self._config = self._load_default_config()
        self._logger = logging.getLogger(__name__)

    def _load_default_config(self) -> Dict[str, Any]:
        """
        加载默认配置
        :return: 默认配置字典
        """
        import os
        return {
            'directories': [os.getcwd()],  # 默认扫描当前工作目录
            'scan_depth': 'recursive',  # 'recursive', 'shallow' 或非负整数
            'hash_algorithm': 'md5',    # 'md5' 或 'sha1'
            'sort_by': 'modified_time',  # 'modified_time', 'created_time', 'accessed_time', 'size', 'name'
            'sort_order': 'descending',  # 'ascending' 或 'descending'
            'log_level': 'info',        # 'debug', 'info', 'warning', 'error', 'critical'
            'delete_confirmation': True,  # 是否需要确认删除
            'show_empty_files': False,   # 是否显示空文件
            'scan_directory_mode': False,  # 是否启用目录扫描模式（向后兼容）
            'scan_mode': 'file',  # 扫描模式: 'file', 'directory', 'empty_directory'
            'compare_filename': False,  # 是否仅比对文件名
            'compare_size': True,        # 是否比对文件大小
            # UI相关配置
            'window_size': {'width': 1024, 'height': 768},  # 窗口大小
            'window_position': {'x': 100, 'y': 100},  # 窗口位置
            'font_size': 10,  # 基础字体大小
            'tree_column_widths': {  # 树形视图列宽配置
                '#0': 60,  # 选择列
                '#1': 50,  # 组#列
                '#2': 400,  # 文件路径列
                '#3': 100,  # 大小列
                '#4': 140,  # 修改时间列
                '#5': 100,  # 哈希值列
                '#6': 80    # 建议列
            }
        }

    def load_config(self) -> bool:
        """
        从配置文件加载配置
        :return: 加载是否成功
        """
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    loaded_config = json.load(f)
                    # 合并加载的配置到当前配置
                    self._config.update(loaded_config)
                    # 验证配置
                    errors = self.validate_config()
                    if errors:
                        self._logger.warning(f'配置验证错误: {errors}')
                        return False
                    return True
            else:
                self._logger.info(f'配置文件 {self.config_file} 不存在，使用默认配置')
                return False
        except Exception as e:
            self._logger.error(f'加载配置失败: {str(e)}')
            return False

    def save_config(self) -> bool:
        """
        保存配置到文件
        :return: 保存是否成功
        """
        try:
            # 验证配置
            errors = self.validate_config()
            if errors:
                self._logger.warning(f'配置无效，无法保存: {errors}')
                return False

            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(self._config, f, ensure_ascii=False, indent=4)
            self._logger.info(f'配置已保存到 {self.config_file}')
            return True
        except Exception as e:
            self._logger.error(f'保存配置失败: {str(e)}')
            return False

    def get_config(self) -> Dict[str, Any]:
        """
        获取当前配置
        :return: 当前配置字典
        """
        return self._config.copy()

    def get(self, key: str, default: Any = None) -> Any:
        """
        获取指定配置项
        :param key: 配置项键名
        :param default: 默认值
        :return: 配置值或默认值
        """
        return self._config.get(key, default)

    def set(self, key: str, value: Any) -> bool:
        """
        设置配置项
        :param key: 配置项键名
        :param value: 配置项值
        :return: 设置是否成功
        """
        # 临时设置并验证
        old_value = self._config.get(key)
        self._config[key] = value
        errors = self.validate_config()
        if errors and key in errors:
            # 如果验证失败，恢复旧值
            self._config[key] = old_value
            self._logger.warning(f'设置配置项 {key} 失败: {errors[key]}')
            return False
        self._logger.info(f'配置项 {key} 已设置为 {value}')
        return True

    def set_many(self, config_dict: Dict[str, Any]) -> Dict[str, str]:
        """
        批量设置配置项
        :param config_dict: 配置字典
        :return: 设置失败的配置项及其错误信息
        """
        errors = {}
        for key, value in config_dict.items():
            # 备份当前值
            old_value = self._config.get(key)
            # 临时设置新值
            self._config[key] = value
            # 验证配置
            validation_errors = self.validate_config()
            if validation_errors and key in validation_errors:
                # 验证失败，恢复旧值并记录错误
                self._config[key] = old_value
                errors[key] = validation_errors[key]
                self._logger.warning(f'设置配置项 {key} 失败: {validation_errors[key]}')
            else:
                # 验证成功
                self._logger.info(f'配置项 {key} 已设置为 {value}')
        return errors

    def reset_to_default(self) -> None:
        """
        重置配置为默认值
        """
        self._config = self._load_default_config()
        self._logger.info('配置已重置为默认值')

    def validate_config(self) -> Dict[str, str]:
        """
        验证配置的有效性
        :return: 无效配置项及其错误信息的字典
        """
        errors = {}

        # 验证扫描深度
        scan_depth = self._config.get('scan_depth')
        if scan_depth not in ['recursive', 'shallow'] and not (isinstance(scan_depth, int) and scan_depth >= 0):
            errors['scan_depth'] = '扫描深度必须是"recursive"、"shallow"或非负整数'

        # 验证哈希算法
        hash_algorithm = self._config.get('hash_algorithm')
        if hash_algorithm not in ['md5', 'sha1']:
            errors['hash_algorithm'] = '哈希算法必须是"md5"或"sha1"'

        # 验证排序依据
        sort_by = self._config.get('sort_by')
        valid_sort_keys = ['modified_time', 'created_time', 'accessed_time', 'size', 'name']
        if sort_by not in valid_sort_keys:
            errors['sort_by'] = f'排序依据必须是{valid_sort_keys}之一'

        # 验证排序顺序
        sort_order = self._config.get('sort_order')
        if sort_order not in ['ascending', 'descending']:
            errors['sort_order'] = '排序顺序必须是"ascending"或"descending"'

        # 验证日志级别
        log_level = self._config.get('log_level')
        valid_log_levels = ['debug', 'info', 'warning', 'error', 'critical']
        if log_level not in valid_log_levels:
            errors['log_level'] = f'日志级别必须是{valid_log_levels}之一'

        # 验证删除确认
        delete_confirmation = self._config.get('delete_confirmation')
        if not isinstance(delete_confirmation, bool):
            errors['delete_confirmation'] = '删除确认必须是布尔值'

        # 验证显示空文件
        show_empty_files = self._config.get('show_empty_files')
        if not isinstance(show_empty_files, bool):
            errors['show_empty_files'] = '显示空文件必须是布尔值'

        # 验证目录扫描模式
        scan_directory_mode = self._config.get('scan_directory_mode')
        if not isinstance(scan_directory_mode, bool):
            errors['scan_directory_mode'] = '目录扫描模式必须是布尔值'

        # 验证扫描模式
        scan_mode = self._config.get('scan_mode')
        valid_scan_modes = ['file', 'directory', 'empty_directory']
        if scan_mode not in valid_scan_modes:
            errors['scan_mode'] = f'扫描模式必须是{valid_scan_modes}之一'
        
        # 验证目录列表
        directories = self._config.get('directories')
        if not isinstance(directories, list):
            errors['directories'] = '扫描目录必须是列表'
        elif len(directories) == 0:
            errors['directories'] = '扫描目录列表不能为空'
        
        # 验证比对选项
        compare_filename = self._config.get('compare_filename')
        if not isinstance(compare_filename, bool):
            errors['compare_filename'] = '仅比对文件名必须是布尔值'
        
        compare_size = self._config.get('compare_size')
        if not isinstance(compare_size, bool):
            errors['compare_size'] = '比对文件大小必须是布尔值'

        # 验证窗口大小配置
        window_size = self._config.get('window_size')
        if not isinstance(window_size, dict) or 'width' not in window_size or 'height' not in window_size:
            errors['window_size'] = '窗口大小必须是包含width和height的字典'
        elif not (isinstance(window_size['width'], int) and window_size['width'] > 0):
            errors['window_size'] = '窗口宽度必须是正整数'
        elif not (isinstance(window_size['height'], int) and window_size['height'] > 0):
            errors['window_size'] = '窗口高度必须是正整数'

        # 验证窗口位置配置
        window_position = self._config.get('window_position')
        if not isinstance(window_position, dict) or 'x' not in window_position or 'y' not in window_position:
            errors['window_position'] = '窗口位置必须是包含x和y的字典'
        elif not isinstance(window_position['x'], int):
            errors['window_position'] = '窗口X坐标必须是整数'
        elif not isinstance(window_position['y'], int):
            errors['window_position'] = '窗口Y坐标必须是整数'

        # 验证字体大小配置
        font_size = self._config.get('font_size')
        if not (isinstance(font_size, int) and font_size > 0):
            errors['font_size'] = '字体大小必须是正整数'

        # 验证树形视图列宽配置
        tree_column_widths = self._config.get('tree_column_widths')
        if not isinstance(tree_column_widths, dict):
            errors['tree_column_widths'] = '树形视图列宽必须是字典'
        else:
            for col, width in tree_column_widths.items():
                if not (isinstance(width, int) and width > 0):
                    errors['tree_column_widths'] = f'列{col}的宽度必须是正整数'
                    break

        return errors


# 测试代码
if __name__ == '__main__':
    # 配置日志
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    # 创建配置管理器实例
    config_manager = ConfigManager('test_config.json')
    
    # 测试默认配置
    print('默认配置:')
    print(config_manager.get_config())
    
    # 测试设置配置项
    print('\n设置配置项:')
    config_manager.set('scan_depth', 2)
    config_manager.set('hash_algorithm', 'sha1')
    print(config_manager.get_config())
    
    # 测试无效配置
    print('\n测试无效配置:')
    result = config_manager.set('scan_depth', -1)
    print(f'设置无效扫描深度结果: {result}')
    
    # 测试保存配置
    print('\n保存配置:')
    result = config_manager.save_config()
    print(f'保存结果: {result}')
    
    # 测试批量设置
    print('\n批量设置配置:')
    errors = config_manager.set_many({
        'sort_by': 'invalid',
        'sort_order': 'ascending',
        'log_level': 'debug'
    })
    print(f'批量设置错误: {errors}')
    
    # 测试重置默认值
    print('\n重置为默认值:')
    config_manager.reset_to_default()
    print(config_manager.get_config())